package carshow;
/*
 * This class functions to capture the replies from the SQL server, which is
 * implemented in SQLiteQS.java, which provides a TCP network port access to
 * the underlying database file kept by SQLite.
 * This is heavily based upon the SocketClient of SocketTest by A. Shetty
 * which is an ancillary tool written to drive the QuickServer package
 * upon which SQLiteQS.java is based.
 * @author: Wayne Motycka
 *
 */
import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;

/**
 * Database response capture & handler class.  This class captures the replies
 * from the SQL requests sent to SQLiteQS over the IP network.
 * It contains customizations that allow it to determine which panel requested
 * the received SQL data and make decisions upon what to do with the data
 * received.  In all cases it should send something back to the UI (which may
 * be part of the stability problems, there may be threads that don't send
 * any kind of reply back)
 * @author wmotycka
 */
public class SqlClientReader extends Thread {
    private static SqlClientReader sqlClient = null;
    private Socket socket = null;
    private carshow.myJTabbedPane fparent;
    private carshow.CarShowUI ui_parent;
    private BufferedInputStream in;
    private static boolean done = false;
    private static boolean debug = false;
    private Stack<String> recv_stack;

    /**
     * sets indication of completed Sql transaction with the server.
     * @param b 
     */
    public void setDone(boolean b) {
        this.done = b;
    }
    public boolean getDone() {
        return done;
    }
    public static void setDebug(boolean b) {
        debug = b;
    }
    /**
     * Implements the singleton pattern on SqlClientReader
     * @param parent the myTabbedPane parent of the CarShowUI jPanel tabs
     * @param s socket to listen on for SQL replies from SQLiteQS server
     *          be it local (localhost) or remote (an IP address)
     */
    private SqlClientReader(Component parent, Socket s) {
        super("SqlClientReader");
        if(parent instanceof javax.swing.JTabbedPane)
            this.fparent = (myJTabbedPane)parent;
        
        else if (parent instanceof carshow.CarShowUI) {
            this.ui_parent = (carshow.CarShowUI)parent;
            parent = null;
        }
        else {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"SqlClientReader parent type passed to constructor");
            if(fparent != null) {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"parent: "+parent.getClass().getName()); 
            }
            else {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).log
                    (Level.INFO,"parent is null, init phase connection");
                this.fparent = (myJTabbedPane) parent;
            }
        }
        if(fparent != null) {
            java.awt.Container ct = fparent;
            do {
                if(ct.getParent() instanceof CarShowUI) {
                    ui_parent = (CarShowUI)ct.getParent();
                    break;
                }
                else ct = ct.getParent();
            } while (ui_parent == null);
        }
        //else {
            // fparent == null , ui_parent may not be (on init...)
        //}
        this.socket = s;
        setDone(false);
        if(socket != null && socket.isClosed()) {
            Logger.getLogger(CarShowUI.class.getName()).log
                (Level.INFO,"clientReader constructor: socket closed?");
        }
    }

    /**
     * SqlClientReader reads from the specified socket and passes responses
     * from the SQLiteQS server (local or remote) on to the parent object
     * which should be a myJTabbedPane object in all cases.
     * @param parent the myJTabbedPane object within CarShowUI
     * @param s the socket to listen on
     * @return
     */
    public static synchronized SqlClientReader capture(Component parent, Socket s) {
        if(sqlClient == null) {
            sqlClient = new SqlClientReader(parent, s);
            //System.err.println("new sqlClient create done");
        }
        else {
            if(sqlClient.socket != null)
                try {
                    sqlClient.socket.close();
                }
                catch (IOException ioe) {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,
            	    "SqlClientReader: close falied on open socket");
                    //parent.disconnect();
                }
        }
        sqlClient.socket = null;
        sqlClient = new SqlClientReader(parent, s);
        sqlClient.start();
        return sqlClient;
    }
    
    /**
     * set the disconnected state for the client reader process which will
     * cause run() method to terminate, ending the poll for more server data.
     * @param b true = disconnected
     */
    public void setDisconnected(boolean b) {
        done=b;
    }
    
    /**
     * runs the listener thread waiting for the reply from the DB server,
     * and parses the value somewhat to determine if it is a return code
     * or a result set (one or more table rows with comma separated values)
     * and examines the destination by asking the myJTabbedPane object in
     * the CarShowUI (the tabbedPane) which panel requested the data.
     * Once the requesting form and data type has been determined, the
     * appropriate reply routine in CarShowUI is called with the result set
     * or return code passed.  Depending upon which CarShowUI routine is called,
     * the data may be again evaluated or simply placed where it belongs on
     * the UI form.
     */
@Override
    public void run() {
        InputStream is = null;
        recv_stack = new Stack();
        if(socket == null) {  // short circuit a missing socket error....
            Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,"run: socket is null!!!");
            if(fparent == null) {
                if(ui_parent != null) {
                    ui_parent.NPEhandler(1);
                    return;
                }
            }
        }
        if (socket.isConnected()) {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"run: socket is connected");
        }
        else { 
            Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,"run: socket is NOT connected!");
            setDone(true);
            ui_parent.clientSocketError(-1);
            return;
        }
        if (socket.isClosed()) {
            Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,"run: Error, Socket status is CLOSED!!!");
            setDone(true);
            ui_parent.clientSocketError(-2);
            return;
        }
        //else System.err.println("run: socket is open...");

        try {
            is = socket.getInputStream();
            in = new BufferedInputStream(is);
        }
        catch (IOException ioe) {
            try { 
                if(socket != null) 
                    socket.close(); 
            } catch (IOException ioe2) {
                Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,"SqlClientReader: socket won't closed after "+
                    "IOE during open: "+ioe2.toString());
            }
            Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,
              "SqlClientReader: socket getInputStream() open failed in run()");
            //ioe.printStackTrace(System.err);
            ui_parent.clientSocketError(-3);
            setDone(true);
            return;
        }
        while(!done) {
            try {
                String recv = readInputStream(in);
                if (recv.contains("EOF")) {
                    recv = recv.substring(0, recv.indexOf("EOF"));
                    if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"run: rcvd string: "+recv);
                    recv = recv.trim();
                    setDone(true);
                }
                String FSEP="\r\n";
                if(recv.length() > 0) {
                    java.util.StringTokenizer st = new java.util.StringTokenizer(recv, FSEP);
                    while(st.hasMoreTokens()) {
                        String nxt = st.nextToken();
                        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"run: pushing token: "+nxt);
                        recv_stack.push(nxt);
                    }
                }
            } catch (IOException ioe) {
                if (!done) {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.SEVERE,
                      "SqlClientReader: stream read failed w/IOException in run()");
                    ioe.printStackTrace(System.err);
                    setDone(true);
                    ui_parent.clientSocketError(-3);
                }
            }
        }
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"Post process SQL data...");
        if(fparent == null) { // in Audit/initialization if fparent == null
            if(ui_parent != null) { // and ui_parent is set to CarShowUI
                if(debug) Logger.getLogger(CarShowUI.class.getName()).
                    log(Level.INFO,"SqlClientReader: actuating setAuditResult in run");
                if(recv_stack != null && recv_stack.size() == 1) {
                    if(ui_parent.getInitState()) 
                        ((CarShowUI)ui_parent).setAuditResult("audit done",
                            Integer.parseInt(recv_stack.pop()));
                    else {
                        ((CarShowUI)ui_parent).setAuditResult("no fparent "
                            +"singleton reply", Integer.parseInt(recv_stack.pop()));
                        Logger.getLogger(CarShowUI.class.getName()).
                            log(Level.INFO,"sqlCleintReader: "+
                            "fparent=null & non UI init state!!");
                    }
                    return;
                }
                else {
                    if(debug) Logger.getLogger(CarShowUI.class.getName()).
                        log(Level.INFO,"Audit result null or > 1, DB rqst OK?");
                    boolean initState = false;
                    if(ui_parent != null) initState = ui_parent.getInitState();
                    if(initState && ui_parent.getServer().equals("localhost")) {
                       ((CarShowUI)ui_parent).setAuditResult("audit done - new tables created", 1);
                    }
                    return;
                }
            }
            else {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).
                    log(Level.INFO,"SqlClientReader: null ui_parent & fparent");
                return;
            }
        }
        if(debug & recv_stack != null) {
            Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"recv_stack size: "+recv_stack.size());
        }
        // FAILURE CASES recv_stack = 0 length
        if(recv_stack.size() == 0) {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"run: 0 length return stack detected");
            Component active_panel = null;
            if(fparent != null) active_panel = fparent.getActiveComponent();
            if (active_panel != null && active_panel.getName().equals("RegistrationPanel"))
                ui_parent.setEntrant(null);
            else if(active_panel != null && active_panel.getName().equals("EntrantClub"))
                ui_parent.setRegClubs(null);
            else if (active_panel != null && active_panel.getName().equals("JudgeSheetPanel"))
                ui_parent.setJudgingEntrant(null);
            else if (active_panel != null && active_panel.getName().equals("JudgeSubPanel"))
                ui_parent.setJudgingData(null);
            else if(active_panel != null && active_panel.getName().equals("JudgingPanel"))
                ui_parent.setJudgePanel(null);
            else if(active_panel != null && active_panel.getName().equals("specialtyAwardsLabel"))
                ui_parent.updateSpecialAwards(null);
            else if(active_panel != null && active_panel.getName().equals("RegPrint"))
                ui_parent.updatePrintStatus(null);
            else if (active_panel != null && active_panel.getName().equals("ClassListTable"))
                ui_parent.setClassList(null);
            else if(active_panel != null && active_panel.getName().equals("AwardsPanel"))
                ui_parent.setAwardsPanel(null);
            else if(active_panel != null && active_panel.getName().equals("ReportTable"))
                ui_parent.setAwardsSaveResult("-9"); // error, unknown cause
            else if(active_panel != null && active_panel.getName().equals("AdminPanel"))
                ui_parent.setContestResult("0"); //empty ShowData table, return a 0
            else if(active_panel != null && active_panel.getName().equals("MostClubMembers"))
                ui_parent.setClubAward(null);
            else if(active_panel != null && active_panel.getName().equals("EntrantDelete"))
                ui_parent.setEntrant(null);
            else if(active_panel != null && active_panel.getName().equals("EntrantClear"))
                ui_parent.setEntrant(null);
            else {
                if(active_panel == null) {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,
                        "sqlClientRdr: null active panel on 0 len stack");
                    ui_parent.clientSocketError(-5);
                }
                else {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,
                        "sqlClientRdr: unclaimed or unrecognized active "+
                        "panel on 0 len stack: "+active_panel.getName());
                    ui_parent.clientSocketError(-6);
                }
                if(fparent != null) fparent.clearWait();
                return;
            }
            if(fparent != null) {
                active_panel = fparent.getActiveComponent();
                if(active_panel != null && active_panel.getName().equals("RegistrationPanel"))
                    ui_parent.setEntrant(null);
                fparent.clearWait();
            }
            return;
        }
        if(fparent.getName() != null) {
            Component active_panel = fparent.getActiveComponent();
            String panelName = null;
            if (active_panel != null) { 
                if(debug)  {
                    Logger.getLogger(CarShowUI.class.getName()).
                    log(Level.INFO,"run: activeComponent name: "+
                    active_panel.getName());
                }
                panelName = active_panel.getName();
                if(panelName == null) {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"getActiveComponent returned null");
                    if(ui_parent != null) ui_parent.clientSocketError(-3);
                    return;
                }
                else if (panelName.equals("RegistrationPanel") || 
                    panelName.equals("EntrantDelete") || panelName.equals("EntrantClear")) {
                    // Entrant data requested
                    popRegistration();
                }
                else if (panelName.equals("JudgeSheetPanel")) {
                    popJudgeSheet();
                }
                else if (panelName.equals("JudgeSubPanel")) {
                    popJudgeSub();
                }
                else if(panelName.equals("AdminPanel")) {
                    popAdmin();
                }
                else if (panelName.equals("AwardsPanel")) {
                    popAwards();
                }
                else if (panelName.equals("specialtyAwardsLabel")) {
                    popSpecials();
                }
                else if (panelName.equals("EntrantClass")) {
                    // handle populating the classes list on the RegistrationPanel
                    popRegClasses();
                }
                else if (panelName.equals("EntrantClub")) {
                    // handle populating the clubs list on the RegistrationPanel
                    popRegClubs();
                }
                else if (panelName.equals("RegPrint")) {
                    popPrinted();
                }
                else if (panelName.equals("JudgingPanel")) {
                    popJudging();
                }
                else if(active_panel.getName().equals("ReportTable"))
                    popPrintResult();
                else if(active_panel.getName().equals("MostClubMembers"))
                    popClubAward();
                else if (active_panel.getName().equals("ClassListTable")) {
                    popClassList();
                }
                else { // un-recognized active panel, send error reply
                    if(ui_parent != null) ui_parent.clientSocketError(-4);
                }
            }
            else { // null active_panel, error in protocol no destination
                if(ui_parent != null) ui_parent.clientSocketError(-4);
            }
        }
    }

    /**
    * Return code handling path on DB print status update request for an
    * entrant.  This pushes the return code value back to the CarShowUI
    * for further handling of the UI behavior post update.
    */
    private void popPrinted() {
        String ret = null;
        if(recv_stack.size() > 0) {
            ret = recv_stack.pop();
        }
        ui_parent.updatePrintStatus(ret);
    }
    /**
     * return path for Awards Print requests back to the UI so the waiting
     * indicators & requests stack can be reset back to the idle state.
     */
    private void popPrintResult() {
        if(recv_stack.size() > 0) {
            String sqlData;
            if (recv_stack.size() == 1 && recv_stack.get(0).contains(",")) {
                ui_parent.setAwardsSaveResult("-9"); // error, unknown cause
            }
            else if (recv_stack.size() == 1) {
                sqlData = recv_stack.pop();
                ui_parent.setAwardsSaveResult(sqlData); // error, unknown cause
            }
        }
        ui_parent.setAwardsSaveResult("-9"); // error, unknown cause
    }
    /**
    * Send the Specials table data received back to the CarShowUI.  Specials
    * data 
    */
    private void popSpecials() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popSpecials:");
        if(recv_stack.size() > 0) {
            String[] sqlData = null;
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log
                (Level.INFO,"recvd "+recv_stack.size()+" elements special rows");
            if(recv_stack.size() == 1 && !recv_stack.get(0).contains(",")) {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).log
                    (Level.INFO,"popSpecials: return code path hit on value: "+
                    recv_stack.get(0));
                String[] ret = new String[1];
                ret[0] = recv_stack.pop();
                ui_parent.updateSpecialAwards(ret);
                return;
            }
            else {
                int i = 0;
                sqlData = new String[recv_stack.size()];
                while(!recv_stack.isEmpty()) {
                    sqlData[i++] = recv_stack.pop();
                }
            }
            ui_parent.updateSpecialAwards(sqlData);
        }
        else {
            // empty result set - send null indicating empty result set
            Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popSpecials: recv_stack = 0 length send null...");
            ui_parent.updateSpecialAwards(null);
        }
    }
    
    /**
     * populate the Administration JPanel from the returned SQL data.  For now
     * the only data saved is the name and date information about the show.
     * The ShowData table is intended to only contain one row, containing
     * this showname/showdate pair.
     */
    private void popAdmin() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popAdmin:"+
            " recv_stack top has: "+recv_stack.peek());
        String ret = null;
        if(recv_stack.empty()) {
            ui_parent.setContestResult("0"); // indicate empty table
        }
        else if(recv_stack.size() >= 1) {
            // weird result set condition expected only a return code
            ret = recv_stack.pop();
        }
        if (ret != null) {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popAdmin:"+
            " sending "+ret+" to setContestResult");
            ui_parent.setContestResult(ret);
        }
        // turn off the Wait... label on the Admin panel
        fparent.clearWait();
    }
    
    /**
     * Populate the club award result to the Awards panel of the UI.  This
     * is a secondary report/request from the UI once the Awards report data
     * has been returned.
     */
    private void popClubAward() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popClubAward:");
        if(recv_stack.size() > 0) { // single club or ret code return
            String[] rets;
            rets = new String[recv_stack.size()];
            int cnt = 0;
            while(!recv_stack.isEmpty())
                rets[cnt++] = recv_stack.pop();
            ui_parent.setClubAward(rets);
        }
        else {
            ui_parent.setClubAward(null);  // indicate empty recv_stack to UI
        }
    }
    /**
     * populate Awards Report Panel in the UI from returned SQL data.
     * 
     */
    private void popAwards() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,
            "popAwards:");
        if(recv_stack.size() > 0) {
            String[] sqlData = null;
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,
                "recvd "+recv_stack.size()+" elements award rpt rows");
            if(recv_stack.size() == 1 && !recv_stack.get(0).contains(",")) {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).
                    log(Level.INFO,"popSpecials: return code path hit on value: "+
                    recv_stack.peek());
                String[] ret = new String[1];
                ret[0] = recv_stack.pop().trim();
                ui_parent.setAwardsPanel(ret);
                return;
            }
            else {
                int i = 0;
                sqlData = new String[recv_stack.size()];
                while(!recv_stack.isEmpty()) {
                    sqlData[i++] = recv_stack.pop();
                }
            }
            ui_parent.setAwardsPanel(sqlData);
        }
        else {
            // empty result set - send null indicating empty result set
            Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popAwards: recv_stack = 0 length send null...");
            ui_parent.setAwardsPanel(null);
        }
        //ui_parent.setAwardsPanel(null);
        //fparent.clearWait();
    }
    /**
     * populate Judging Sheet JPanel with SQL data.  The SQL from this
     * call should only contain the registration data for the entrant
     * on the initial search when you tab/lose focus to the JS_EntrantNum
     * field of JudgingSheet tab
     * 
     */
    private void popJudgeSheet() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popJudgeSheet: stack size: "+recv_stack.size());
        String[] sqlData;
        if(recv_stack.size() > 0) {
            sqlData = new String[recv_stack.size()];
            if(recv_stack.size() == 1) { //this is what is should be always
                sqlData = new String[1];
                sqlData[0] = recv_stack.pop();
                ui_parent.setJudgingEntrant(sqlData);
            }
            else {
                Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"multiple rows on popJudgeSeet return!");
                sqlData = new String[1];
                sqlData[0] = recv_stack.pop();
                ui_parent.setJudgingEntrant(sqlData);
            }
        }
        fparent.clearWait();
    }
    /**
     * populate the Judging Sheet sub JPanel with SQL data.
     * The data received here will be judging data from the Scoring DB
     */
    private void popJudgeSub() {
        if(debug) {
            Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,
              "popJudgeSub: recv_stack size:"+recv_stack.size()+
              " value: "+recv_stack.peek());
        }
        String[] sqlData;
        if(recv_stack.size() > 0) {
            sqlData = new String[recv_stack.size()];
            if(recv_stack.size() >= 1) {
                sqlData = new String[1];
                sqlData[0] = recv_stack.pop();
                ui_parent.setJudgingData(sqlData);
            }
        }
        //fparent.clearWait();
    }
    /**
     * Populate the Judging JPanel with SQL data.  This is done on a periodic
     * timer by the UI with the SQL data reply path through here back to the
     * CarShowUI.setJudgePane() method.
     */
    private void popJudging() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popJudging:");
        String[] sqlData;
        if(recv_stack.size() > 0) {
            sqlData = new String[recv_stack.size()];
            if(recv_stack.size() == 1) {
                sqlData = new String[1];
                sqlData[0] = recv_stack.pop();
            }
            else {
                sqlData = new String[recv_stack.size()];
                java.util.Iterator it = recv_stack.iterator();
                int idx = 0;
                while(it.hasNext()) {
                    sqlData[idx++] = (String)it.next();
                    //System.err.println("popJudging: sqlData["+(idx-1)+"]="+sqlData[idx-1]);
                }
            }
        }
        else  {
            Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popJudging: recv_stack size 0");
            sqlData = new String[1];
            sqlData[0] = "-1";
        }
        ui_parent.setJudgePanel(sqlData);
        //fparent.clearWait();

    }
    /**
     * populate the Registration JPanel with SQL data
     * received in run() above.  Stored in recv_stack() object
     * If the result set in recv_stack is a single number, this was
     * an update rather than a select (view).
     */
    private void popRegistration() {
        if(recv_stack.size() > 0) {
            if(recv_stack.size() == 1) {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegistration: --pop stack--");
                String sqlData = recv_stack.pop();
                if(sqlData.length() <= 3 && sqlData.length() > 0) {
                    if(sqlData.matches("[0-9]+")) {
                        String panelName = fparent.getActiveComponent().getName();
                        if(panelName.equals("EntrantDelete") ||
                                panelName.equals("EntrantClear")) { // rmv entrant Scoring data
                            ui_parent.setEntrant(null);
                        }
                        else ui_parent.updEntrant(sqlData);
                    }
                    else {
                        ui_parent.setEntrant(null);
                    }
                }
                else
                    ui_parent.setEntrant(sqlData);
            }
            else {
                if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"multir row reply, generate set");
                int i = 0;
                String[] sqlData = new String[recv_stack.size()];
                while(!recv_stack.isEmpty()) {
                    sqlData[i++] = recv_stack.pop();
                }
                ui_parent.setMultiEntrant(sqlData);
            }
        }
        else {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegistration: recv_stack = 0 length - CLEAR ENTRANT!!!");
            ui_parent.clearEntrant();
        }
        //fparent.clearWait();
    }

    /**
     * populate the car classes dropdown on the Registration panel
     */
    private void popRegClasses() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegClasses: recv_stack size:"+recv_stack.size());
        if(recv_stack.size() > 0) {
            int rsize = recv_stack.size();
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegClasses: populate Reg Classes");
            String[] sqlData = new String[rsize];
            int i = 0;
            while(!recv_stack.isEmpty()) {
                sqlData[i++] = recv_stack.pop();
            }
            ui_parent.setRegClasses(sqlData);
        }
        fparent.clearWait();
    }

    /**
     * Sets the clubs list on the Registration panel.
     */
    private void popRegClubs() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegClubs");
        if(recv_stack.size() > 0) {
            if(debug && recv_stack.size() == 1) {
                Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegClubs: recv_stack size == 1 ");
            }
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popRegClubs: populate clubs list");
            String[] sqlData = new String[recv_stack.size()];
            int i = 0;
            while(!recv_stack.isEmpty()) {
                sqlData[i++] = recv_stack.pop();
            }
            ui_parent.setRegClubs(sqlData);
        }
        //fparent.clearWait();
    }

    /**
     * populate the ClassListTable of the Class Setup panel of the UI.  This
     * will detect if the operation was an insert/delete (detects a return
     * value instead of column data) and performs a call back instructing the
     * UI to refresh the class set (by another DB call) this keeps the data
     * fresh in the UI.
     */
    private void popClassList() {
        if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"popClassList");
        if(recv_stack.size() > 0) {
            if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"populate class form table");
            if((recv_stack.size() == 1)) { // sqlPut() returns a single int
                String retv = recv_stack.pop();
                boolean intval = false;
                try {
                    int reti = Integer.parseInt(retv);
                    intval = true;
                } catch (NumberFormatException nfe) {
                    Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"return value: "+retv+" not a number!");
                    intval=false;
                }
                if(intval) {
                    // call appropriate subroutine on in CarShowUI
                    // that will request a repaint of the class list
                    if(debug) Logger.getLogger(CarShowUI.class.getName()).log(Level.INFO,"intval flag true clearWait and resetClassTable");
                    fparent.clearWait();
                    ui_parent.resetClassTable();
                }
                else { // non-humeric ret == single sql row return
                    String[] sqlData = new String[1];
                    sqlData[0] = retv;
                    ui_parent.setClassList(sqlData);
                }
            }
            else { // rcv_stk > 1, sql resultSet rows return
                String[] sqlData = new String[recv_stack.size()];
                java.util.Iterator iter = recv_stack.iterator();
                int i = 0;
                while(iter.hasNext()) {
                    sqlData[i++] = (String)iter.next();
                }
                if(recv_stack.size() > 0) recv_stack.clear();
                ui_parent.setClassList(sqlData);
            }
        }
    }

    private static String readInputStream(BufferedInputStream _in) throws IOException {
        String data = "";
        int s = _in.read();
        if(s==-1)
            return null;
        data += ""+(char)s;
        int len = _in.available();
        //System.out.println("Len got : "+len);
        if(len > 0) {
            byte[] byteData = new byte[len];
            _in.read(byteData);
            data += new String(byteData);
        }
        return data;
    }
}